#include "stdafx.h"
#include "gamehandler.h"
#include <model/scene.h>
#include <model/sceneanimator.h>
#include <model/mage.h>
#include <model/potion.h>
#include <model/vec2.h>

#include <vector>

static const unsigned MIN_INTERVAL = 10;
static const unsigned MAX_INTERVAL = 100;

class GameHandlerPrivate
{
public:
    QTimer timer;
    QTimer bonusTimer;

    std::unique_ptr<Scene> scene;
    std::unique_ptr<SceneAnimator> animator;
    std::vector<Player> players;

    bool locked;
    bool playersAreDeprecated;
    unsigned turnNo;

    unsigned width;
    unsigned height;
    unsigned interval;
    unsigned bonusInterval;

    GameHandlerPrivate():
        scene(nullptr),
        animator(nullptr),
        locked(false),
        playersAreDeprecated(false),
        turnNo(0),
        width(800),
        height(600),
        interval(MIN_INTERVAL),
        bonusInterval(300)
    {
    }

    vec2f makePosition(unsigned playerIndex)
    {
        static const vec2f SCALES[4] = {
            vec2f(0.2, 0.2),
            vec2f(0.2, 0.8),
            vec2f(0.8, 0.8),
            vec2f(0.8, 0.2)
        };
        playerIndex = playerIndex % GameHandler::MAX_PLAYERS;
        const vec2f &scale = SCALES[playerIndex];

        return vec2f(width * scale.x, height * scale.y);
    }
};

GameHandler::GameHandler():
    d(new GameHandlerPrivate())
{
}

GameHandler::~GameHandler()
{
    delete d;
}

const Player &GameHandler::player(int index) const
{
    int size = d->players.size();
    if (index < -size || index >= size)
        return d->players[0];

    if (index < 0)
        index += size;
    return d->players[index];
}

const Scene *GameHandler::scene() const
{
    if (!d->locked)
        return nullptr;
    return d->scene.get();
}

bool GameHandler::locked() const
{
    return d->locked;
}

int GameHandler::addPlayer(const Player &player)
{
    if (d->locked)
        return -1;

    if (d->playersAreDeprecated) {
        d->playersAreDeprecated = false;
        d->players.clear();
    }

    if (d->players.size() >= MAX_PLAYERS)
        return -1;

    d->players.push_back(player);
    return (d->players.size() - 1);
}

bool GameHandler::setSize(unsigned width, unsigned height)
{
    if (d->locked)
        return false;

    d->width = width;
    d->height = height;
    return true;
}

bool GameHandler::setInterval(unsigned interval)
{
    if (d->locked)
        return false;

    if (interval < MIN_INTERVAL)
        d->interval = MIN_INTERVAL;
    else if (interval > MAX_INTERVAL)
        d->interval = MAX_INTERVAL;
    else
        d->interval = interval;

    return true;
}

bool GameHandler::startGame()
{
    if (d->locked)
        return false;

    d->locked = true;
    d->turnNo = 0;
    d->playersAreDeprecated = true;

    d->scene.reset(new Scene(d->width, d->height));
    d->animator.reset(new SceneAnimator(d->scene.get()));

    for (size_t index = 0; index < d->players.size(); ++index) {
        Mage *mage = new Mage(d->makePosition(index));
        d->scene.get()->registerObject(mage);
        d->players[index].setMage(mage);
    }

    connect(&d->timer, SIGNAL(timeout()), this, SLOT(onTimer()));
    connect(&d->bonusTimer, SIGNAL(timeout()), this, SLOT(onBonusTimer()));
    d->timer.start(d->interval);
    d->bonusTimer.start(d->bonusInterval);
    emit gameStart();
    return true;
}

void GameHandler::onTimer()
{
    for (size_t index = 0; index < d->players.size(); ++index) {
        Player &player = d->players[index];
        auto action = player.askControl(d->scene.get());
        if (action == ISelfControl::Action_Staff) {
        }
    }
    d->scene->accept(d->animator.get());
    d->scene->detectCollisions();

    emit turnEnd();
    ++d->turnNo;
}

void GameHandler::onBonusTimer()
{
     d->scene->addPotion();
     d->bonusTimer.setInterval(d->scene->getPotionsNum()*d->bonusInterval);
}
